﻿using System;
using System.Collections.Generic;
using System.Reflection;
using MyORM.attr;
using System.Text;

namespace MyORM.mapper
{
    public class TableStruct
    {
        private object obj;
        private Dictionary<string, PropertyInfo> columns;
        private List<string> primaryKeys;
        private string tableName;

        public TableStruct(object obj)
        {
            this.obj = obj;
            object[] temps = obj.GetType().GetCustomAttributes(typeof(Table), false);
            if (temps.Length > 0)
            {
                this.tableName = ((Table)temps[0]).tableName;
                PropertyInfo[] fields = obj.GetType().GetProperties();
                if (fields.Length > 0)
                {
                    object[] objs;
                    columns = new Dictionary<string, PropertyInfo>();
                    primaryKeys = new List<string>();
                    foreach (PropertyInfo field in fields)
                    {
                        objs = field.GetCustomAttributes(false);
                        if (objs.Length > 0)
                        {
                            foreach (object o in objs)
                            {
                                if (o is Column)
                                {
                                    columns.Add(((Column)o).columnName, field);
                                }
                                else if (o is Id)
                                {
                                    primaryKeys.Add(((Id)o).columnName);
                                }
                            }
                        }
                    }
                }
            }
        }

        internal Dictionary<int, object> BuildDict(string type)
        {
            if (primaryKeys.Count > 0)
            {
               object pkValue = columns[primaryKeys[0]].GetValue(this.obj, null);
               if (pkValue != null)
                   return buildUpdate(true);
               return buildInsert(true);
            }
            return buildInsert(false);
        }

        private Dictionary<int, object> buildUpdate(bool notNull)
        {
            Dictionary<int, object> sqlDict = new Dictionary<int, object>();
			StringBuilder sql1 = new StringBuilder(" set ");
			int j = 1;
			if (notNull)
			{
				object val = null;
				foreach (string key in columns.Keys)
				{
					val = columns[key].GetValue(this.obj, null);
					if (primaryKeys != null && !primaryKeys.Contains(key) && val != null)
					{
						sql1.Append("" + key + "=@").Append(j - 1).Append(",");
						sqlDict.Add(j, val);
						j++;
					}
				}
			}
			else
			{
				foreach (string key in columns.Keys)
				{
					if (primaryKeys != null && !primaryKeys.Contains(key))
					{
						sql1.Append("" + key + "=@").Append(j - 1).Append(",");
                        sqlDict.Add(j, columns[key].GetValue(this.obj, null));
						j++;
					}
				}
			}
			sql1.Remove(sql1.Length - 1, 1);
			StringBuilder sql2 = new StringBuilder();
			if(primaryKeys != null && primaryKeys.Count > 0)
			{
				foreach (string key in primaryKeys)
				{
                    sql2.Append("" + key + "=@").Append(j - 1).Append(" AND ");
                    sqlDict.Add(j, columns[key].GetValue(this.obj, null));
					j++;
				}
			}
			if(sql2.Length > 0)
                sql2.Remove(sql2.Length - 4, 4);
            String sql = "update " + this.tableName + sql1.ToString() + " where " + sql2.ToString();
            sqlDict.Add(0, sql);
            return sqlDict;
        }

        private Dictionary<int, object> buildInsert(bool identity)
        {
            Dictionary<int, object> sqlDict = new Dictionary<int, object>();
            StringBuilder sql1 = new StringBuilder("(");
            StringBuilder sql2 = new StringBuilder("(");
            int j = 1;
            object val = null;
            foreach (string key in columns.Keys)
            {
                val = columns[key].GetValue(this.obj, null);
                if (val != null)
                {
                    sql1.Append("" + key + ",");
                    sql2.Append("@").Append(j - 1).Append(",");
                    sqlDict.Add(j, val);
                    j++;
                }
            }
            sql1.Remove(sql1.Length - 1, 1);
            sql1.Append(")");
            sql2.Remove(sql2.Length - 1, 1);
            sql2.Append(")");
            string sql = "insert into " + this.tableName + sql1.ToString() + " values " + sql2.ToString();
            if (identity)
                sql += ";SELECT @ide=@@IDENTITY";
            sqlDict.Add(0, sql);
            return sqlDict;
        }

        internal void updateId(int pkValue)
        {
            if (primaryKeys.Count > 0)
            {
                columns[primaryKeys[0]].SetValue(this.obj, pkValue, null);
            }
        }
    }
}
